{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9bee88b7-f1fb-4eae-818c-d9e215eb016b",
   "metadata": {
    "tags": []
   },
   "source": [
    "# pyqtgraph对比matplotlib的优缺点\n",
    "### 优点\n",
    "1. pyqtgraph对python/qt程序员更直观。\n",
    "2. 包含有图像交互，体绘制，参数树，流程图等功能\n",
    "3. 更快！特别是大量数据或者动态更新的图片，天壤之别！\n",
    "\n",
    "### 缺点\n",
    "1. 不够matplotlib完善，静态图片没有matplotlib漂亮\n",
    "\n",
    "## 使用建议\n",
    "graph用来研究，matplotlib用来给出版物画图\n",
    "\n",
    "## 参考文献来源\n",
    "[pyqtgraph中文文档](https://blog.csdn.net/Eppley/article/details/82999998)\n",
    "有进一步需要的话还是要去看官方文档，虽然大概率也看不懂啥。。实在不知道想实现的功能在哪学，不如去拆解example算了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ee12fce-f601-4d1a-9d2e-12800ca976b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 打开pyqtgraph的案例库\n",
    "import pyqtgraph.examples\n",
    "pyqtgraph.examples.run()\n",
    "\"\"\"\n",
    "注意如果你已经用python setup.py开发安装pyqtgraph，那么这些例子就会被错误地提示为top-level module。 \n",
    "在这种情况下，使用导入示例：examples.run（）。\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7dd8922b-1f4b-434f-b901-3101e0db0768",
   "metadata": {},
   "source": [
    "# 主要绘图函数\n",
    "1. pg.plot\n",
    "2. pg.image\n",
    "3. pg.sho"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1bd8f2b-3654-415c-ab41-da9a5d1842fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入包并且定义示例数据。\n",
    "import numpy as np\n",
    "import pyqtgraph as pg\n",
    "data1D_random = np.random.normal(size=1000)\n",
    "data2D_random = np.random.normal(size=(500,500))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a7750ca-e4ea-4194-85aa-e519b8963df8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 先看看画出来是什么效果，下面再详细解释\n",
    "pg.plot(data1D_random, title=\"Simplest possible plotting example\")# data can be a list of values or a numpy array\n",
    "pg.image(data2D_random, title=\"Simplest possible image example\")# data can be a list of values or a numpy array\n",
    " \n",
    "## Start Qt event loop unless running in interactive mode or using pyside.\n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()\n",
    "        \"\"\"\n",
    "        如果不附加这一段Qt event Loop的话，可能会导致GUI出现无响应的情况，例如下面的这个例子。\n",
    "        \"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48de31c2-adbb-4f8b-8b92-5c08f58f923a",
   "metadata": {},
   "outputs": [],
   "source": [
    "pg.show(data2D_random)  # imageData must be a numpy array with 2 to 4 dimensions\n",
    "# 运行该段代码GUI会进入无响应状态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e969b51b-c0b2-47c7-b3aa-53bec292be22",
   "metadata": {},
   "outputs": [],
   "source": [
    "pg.show(data2D_random)  \n",
    "# 添加Qt event loop\n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()\n",
    "        \"\"\"\n",
    "        现在可以正常运行了\n",
    "        注意：python提示符中的交互式绘图仅适用于PyQt; 在交互式提示符运行时，PySide不运行Qt事件循环。\n",
    "        如果你想与PySide交互使用pyqtgraph，请参阅'console'示例。\n",
    "        \"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e9611f4-f75f-4077-8097-f990d0eab887",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8631b107-1870-4c92-976c-3d5be291d71f",
   "metadata": {},
   "outputs": [],
   "source": [
    "pw = pg.plot(xVals, yVals, pen='r')  # plot x vs y in red\n",
    "pw.plot(xVals, yVals2, pen='b')\n",
    " \n",
    "win = pg.GraphicsWindow()  # Automatically generates grids with multiple items\n",
    "win.addPlot(data1, row=0, col=0)\n",
    "win.addPlot(data2, row=0, col=1)\n",
    "win.addPlot(data3, row=1, col=0, colspan=2)\n",
    " \n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce0b7caa-3021-4221-9cc3-f60cd2245af8",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "## Plotting in pyqtgraph\n",
    "在pyqtgraph中有四个基本的画图函数：\n",
    "\n",
    "| [`pyqtgraph.plot()`](https://pyqtgraph.readthedocs.io/en/latest/functions.html#pyqtgraph.plot) | Create a new plot window showing your data       |\n",
    "| ------------------------------------------------------------ | ------------------------------------------------ |\n",
    "| [`PlotWidget.plot()`](https://pyqtgraph.readthedocs.io/en/latest/widgets/plotwidget.html) | Add a new set of data to an existing plot widget |\n",
    "| [`PlotItem.plot()`](https://pyqtgraph.readthedocs.io/en/latest/graphicsItems/plotitem.html#pyqtgraph.PlotItem.plot) | Add a new set of data to an existing plot widget |\n",
    "| [`GraphicsLayout.addPlot()`](https://pyqtgraph.readthedocs.io/en/latest/graphicsItems/graphicslayout.html#pyqtgraph.GraphicsLayout.addPlot) | Add a new plot to a grid of plots                |\n",
    "\n",
    "他们都是类(class)，需要经过实例化后，在实例上应用各种方法。\n",
    "\n",
    "所有这些方法都接收相同的基本参数，这些参数控制如何绘制数据和显示图形：\n",
    "### 接受参数\n",
    "\n",
    "\n",
    "\n",
    "x - 可选的X数据; 如果未指定，则会自动生成一系列整数。\n",
    "y - Y数据。\n",
    "\n",
    "    1. 输入一个(N, )数据，则以数组序号作为x轴，值作为y轴画图。\n",
    "    2. 输入两个(N, )输入，如下案例所示，分别作为x和y轴数据进行画图。\n",
    "\n",
    "\n",
    "\n",
    "pen - 绘制绘图线时使用的笔，或者指定为**None**以禁用线\n",
    "\n",
    "symbol - 描述用于每个点的符号形状的字符串。 可选地，这也可以是对于每个点具有不同符号的字符串序列。\n",
    "\n",
    "symbolPen - 绘制符号轮廓时使用的笔（或笔序列）。\n",
    "\n",
    "symbolBrush - 填充符号时使用的画笔（或画笔序列）。\n",
    "\n",
    "fillLevel - 填充曲线下面的区域为该Y值。\n",
    "\n",
    "brush - 填充曲线时使用的笔刷。\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76dffcfb-c7fa-4b5d-a2e6-fd873690bee7",
   "metadata": {},
   "outputs": [],
   "source": [
    "xVals = np.arange(0,2,0.1)\n",
    "yVals = np.arange(10,30)\n",
    "\n",
    "pw = pg.plot(xVals, yVals, pen='r')  # plot x vs y in red\n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70b3ed8c-fd04-4ca5-84e9-d30df971e7e0",
   "metadata": {},
   "source": [
    "### 画散点图\n",
    "删除线，打开点，就是散点图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71c95349-ea6c-41c4-acfc-1cd32a920c12",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "pg.plot(xVals, yVals, pen=None, symbol='o')  ## setting pen=None disables line drawing\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "06d1219f-9692-4c27-9d3b-9ff17b0e990d",
   "metadata": {},
   "source": [
    "pw = xx\n",
    "pw. 的方法来修改这个画图，就是整个画布\n",
    "\n",
    "如果再来一次pw = ddd 其实是新建一个画布，并且重新命名为pw，之前那个的名字就被顶掉了。无法操控了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c04593f-284a-4f87-8c59-4e1a59a7ec84",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "pw = pg.plot(xVals, yVals, pen='r')  # plot x vs y in red\n",
    "pw.plot(xVals, yVals, pen='b')\n",
    "pw = pg.plot(xVals, yVals, pen='r') \n",
    "pw.plot(xVals, yVals, pen='g')\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "25514d6a-ab11-4f43-8cfd-7c20c490a8f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "#win = pg.GraphicsWindow()  # Automatically generates grids with multiple items\n",
    "#win.addPlot(data21_random, row=0, col=0)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf3e581e-6225-434f-8cae-8c1bbc90ecfa",
   "metadata": {},
   "source": [
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be49db32-9341-4c1d-ad21-6555a9090b99",
   "metadata": {},
   "source": [
    "# 画图窗口设置\n",
    "主要通过指定一个widget，然后对widget使用方法来添加属性。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d12be37-05e7-4c76-8d14-c3cb560cdbc9",
   "metadata": {},
   "source": [
    "## 同框画多图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c2fca12-53ed-4d2f-9fce-68fba9115571",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "x = np.arange(1000)\n",
    "y = np.random.normal(size=(3, 1000))  # 生成三个1000长度的随机归一化一维数组\n",
    "plotWidget = pg.plot(title=\"Three plot curves\")\n",
    "\"\"\"\n",
    "指定一个plotWidget的widget，相当于是一个画图对象。\n",
    "基本属性是带title的plot\n",
    "\"\"\"\n",
    "for i in range(3):  # 给plotWidget添加属性\n",
    "    plotWidget.plot(x, y[i], pen=(i,3))  # 对同一个x，依次用3个随机数组画图，每个数组对应一个颜色\n",
    "    \"\"\"pen =(i,3)可以依次指定颜色\"\"\"\n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    import sys\n",
    "    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):\n",
    "        pg.QtGui.QApplication.exec_()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "817d92bf-906f-49b0-80ea-1b5359510eae",
   "metadata": {},
   "source": [
    "## [指定线型和填充颜色](https://blog.csdn.net/Eppley/article/details/82999998#:~:text=%E5%8D%81%E3%80%81-,%E7%BA%BF%EF%BC%8C%E5%A1%AB%E5%85%85%E5%92%8C%E9%A2%9C%E8%89%B2,-Qt%E4%BE%9D%E9%9D%A0%E5%AE%83%E7%9A%84)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f07e24f-a9ce-4578-83c1-957226de3c5c",
   "metadata": {},
   "source": [
    "## 画图GUI中的鼠标操作\n",
    "可以完成坐标轴调整、透明度调整等等功能"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ab46a93-1c2e-4d70-94d3-95725e8bceb4",
   "metadata": {},
   "source": [
    "# 其他使用方法\n",
    "## [显示图片和视频](https://blog.csdn.net/Eppley/article/details/82999998#:~:text=%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C%EF%BC%9A-,%E5%85%AB%E3%80%81%E6%98%BE%E7%A4%BA%E5%9B%BE%E5%83%8F%E5%92%8C%E8%A7%86%E9%A2%91,-PyQtGraph%E5%B0%862D)\n",
    "## [交互式控件](https://blog.csdn.net/Eppley/article/details/82999998#:~:text=%E5%8D%81%E4%B8%80%E3%80%81-,%E4%BA%A4%E4%BA%92%E5%BC%8F%E6%95%B0%E6%8D%AE%E9%80%89%E6%8B%A9%E6%8E%A7%E4%BB%B6,-PyQtGraph%E5%8C%85%E5%90%AB%E5%9B%BE%E5%BD%A2)\n",
    "## [导出图像和三维图形](https://blog.csdn.net/Eppley/article/details/82999998#:~:text=%E5%8D%81%E4%BA%8C%E3%80%81-,%E5%AF%BC%E5%87%BA,-PyQtGraph%E4%B8%BA%E6%89%80%E6%9C%89) （可以在代码或GUI界面导出）\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed8033e6-bd86-466d-a33f-571bfaeb035b",
   "metadata": {},
   "source": [
    "## [PyQt5 pyqtgraph 实时绘制数据](https://blog.csdn.net/weixin_40796925/article/details/107733966)\n",
    "下面是修改自上述连接内的示范代码\n",
    "\n",
    "[pyqtgragh——动态数据可视化：绘制静态和动态两种数据曲线](https://blog.csdn.net/qq_45779334/article/details/113095313#:~:text=pyqtgraph%E7%9A%84%E7%BB%98%E5%9B%BE%E6%95%B0%E6%8D%AE%E4%B8%BB%E8%A6%81%E6%98%AF%E9%80%9A%E8%BF%87%20setData%20%28%29%20%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E6%9D%A5%E8%BD%AC%E5%8C%96%E4%B8%BA%E5%9B%BE%E5%BD%A2%E3%80%82,%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%B8%AA%E5%AE%9A%E6%97%B6%E5%99%A8%EF%BC%8C%E6%AF%8F%E9%9A%94%E4%B8%80%E4%B8%AA%E6%97%B6%E9%97%B4%E9%87%8D%E6%96%B0%E8%B0%83%E7%94%A8%20setData%20%28%29%20%E6%96%B9%E6%B3%95%E5%AF%B9%E5%9B%BE%E5%BD%A2%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E8%AE%BE%E7%BD%AE%EF%BC%8C%E5%B0%B1%E8%83%BD%E5%A4%9F%E5%AE%9E%E7%8E%B0%E5%AE%9E%E6%97%B6%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96%E5%91%88%E7%8E%B0%E3%80%82)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b2cb0c9-fe62-4197-967c-391d1775e161",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "实时更新图绘制示例代码（修改自超链接内）\n",
    "\"\"\"\n",
    "# 定义示范数据，代表速度分别为1, 2, 3的三个小物体在移动，通过一个3*600的矩阵放置三个物体各自600个位置.\n",
    "data = np.arange(0, 600)\n",
    "car_data_pos = [data , data*2, data*3]\n",
    "car_data_pos = np.asanyarray(car_data_pos)\n",
    "# 定义实时绘图类\n",
    "class Window(QWidget):\n",
    "    def __init__(self):\n",
    "        super().__init__()  # 继承QWidget类的init方法\n",
    "        self.resize(600,600)# 设置窗口尺寸\n",
    "        self.plotWidget_ted = PlotWidget(self)# 添加 PlotWidget 控件\n",
    "        self.plotWidget_ted.setGeometry(QtCore.QRect(25,25,550,550))# 设置该绘图控件尺寸和相对窗口的位置\n",
    "        # 初始化绘图数据\n",
    "        self.data = car_data_pos[:, 0]\n",
    "        self.curve1 = self.plotWidget_ted.plot(self.data,\n",
    "                                               name = \"mode1\", \n",
    "                                               pen = None, symbol = 'o')\n",
    "       \n",
    "        self.timer = pq.QtCore.QTimer() # 设定定时器\n",
    "        self.timer.timeout.connect(self.update_data)# 定时器信号绑定 update_data 函数\n",
    "        self.timer.start(100)  # 设定刷新间隔(ms)\n",
    "\n",
    "    def update_data(self):\n",
    "        \"\"\"数据更新函数\"\"\"\n",
    "        # 指定一个全局的i变量，用以在每次更新时索引数据。（索引完数据后会报错，暂时懒得改）\n",
    "        global i  \n",
    "        i += 1\n",
    "        # 更新绘图数据\n",
    "        self.data = car_data_pos[:, i]  \n",
    "        self.curve1.setData(self.data)  # 会同时对x和y的数据都进行更新。\n",
    "        \"\"\"\n",
    "        如果输入的数据包括x轴和y轴，则更新时需要写成如下格式\n",
    "        self.curve1.setData(x = xVal, y = yVal)\n",
    "        \"\"\"\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    i = 0  # 每次运行重置i变量\n",
    "    import sys\n",
    "    app = QApplication(sys.argv)# PyQt5 程序固定写法\n",
    "\n",
    "    # 将绑定了绘图控件的窗口实例化并展示\n",
    "    window = Window()\n",
    "    window.show()\n",
    "\n",
    "    sys.exit(app.exec())# PyQt5 程序固定写法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7b4ff44-a1c4-4982-8ee8-9c26c5fd9282",
   "metadata": {},
   "source": [
    "**给python新手的说明:**\n",
    "想要看懂这里的画图方法，需要先学会python的类(class）概念和实例的概念。\n",
    "\n",
    "Qwidget是整个画图依附的类，我们创建Window类并继承Qwidget的方法等信息。在window类中定义了新的实例数据以及up_data方法。随后使用pyqt的QtCore.QTimer函数作为定时器，反复地调用window类中的方法进行画图和数据更新。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ffbd7e1-9439-4871-b6bd-e7a6e3b73857",
   "metadata": {},
   "source": [
    "## [获取鼠标所处位置的数据值](https://www.cnblogs.com/wuyuan2011woaini/p/14756070.html#:~:text=%2B%20View%20Code-,%E8%8E%B7%E5%8F%96%E9%BC%A0%E6%A0%87%E6%89%80%E5%9C%A8%E5%A4%84%E5%88%BB%E5%BA%A6%E5%80%BC,-%E6%9C%89%E6%97%B6%E5%80%99%EF%BC%8C%E6%88%91%E4%BB%AC)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ae0a714-e270-4a87-9606-0b83087c4664",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
